
<script setup>
import List from "../component/List.vue";
import ClusterNamespaceSelector from "../component/ClusterNamespaceSelector.vue";
import { getPodListHandler as getListHandler } from "../../api/pod.js";
import { reactive, onBeforeMount, computed, ref, toRefs, onMounted } from "vue";
import CodeMirror from "../component/CodeMirror.vue";
import { obj2Yaml } from "../../utils/utils.js";
// 导入xtermjs
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
import { FitAddon } from "xterm-addon-fit";
import { AttachAddon } from "xterm-addon-attach";
import { ElMessage } from "element-plus";


let drawer = ref(false)
let currentPod = ref()
let currentContainer = ref()
let currentOptions = ref()
let curWs = ""
let logContent = ref([]) 
let term = ""
let fitAddon = ""
let defaultCommand = "/bin/bash"

const data = reactive({
  items: [],
  clusterId: "",
  namespace: "",
  yamlContent: "",
  clusterList: "",
  termOptions: {
    // 渲染窗口的类型
    rendererType: 'canvas',
    // 行数，最小高度
    rows: 15,
    // 列数，最小宽度
    cols: 100,
    // 光标设置为下一行的开头
    convertEol: true,
    // 光标闪烁
    cursorBlink: true,
    theme: {
      foreground: 'yellow', //字体
      background: '#060101', //背景色
      lineHeight: 16,
      // 光标样式
      cursor: 'help'
    }
  }
});

onMounted(()=> {
  // 先去初始化terminal
  term = new Terminal(data.termOptions);
  // fitaddon: 定义窗口自适应
  fitAddon = new FitAddon()
  term.loadAddon(fitAddon)
})

// 定义一个查询Pod列表的函数
const getList = () => {
  getListHandler(data.clusterId, data.namespace).then((res) => {
    data.items = res.data.data.items;
  });
  console.log("res", data.items);
};
// 回调函数
const rollback = (clusterId, namespace) => {
  data.clusterId = clusterId;
  data.namespace = namespace;
  getList();
};

onBeforeMount(async () => {
  // 查询列表之前，要知道哪个集群的节点列表
  // 1、查询到集群列表
  // 2、如果没有指定集群，则给一个默认值，进行获取集群列表
  // 3、如果指定了集群，就直接查询当前集群的节点列表
  // 4、切换了集群之后，应该重新获取集群列表
  // 5、集群不可用，则不可选
  await getList();
  const defaultClusterSelected = data.clusterList[0].id;
  // 获取当前请求是否携带了集群ID的参数
  const curClusterId = route.query.clusterId;
  data.clusterId = curClusterId ? curClusterId : defaultClusterSelected;

  getList(data.clusterId);
});

const search = ref("");

const filterTableData = computed(() =>
  data.items.filter(
    (item) =>
      !search.value ||
      item.metadata.name.toLowerCase().includes(search.value.toLowerCase()) ||
      item.status.addresses[0].address
        .toLowerCase()
        .includes(search.value.toLowerCase())
  )
);

// 删除的方法
const deleteItem = (row) => {
  console.log("删除：", row);
};

// 判断pod的重启次数和容器状态
const getPodRestartCount = computed(() => (row) => {
  let restartCount = 0;
  let readyCount = 0;
  row.status.containerStatuses.forEach((item) => {
    restartCount += item.restartCount;
    if (item.ready) {
      readyCount += 1;
    }
  });
  const containerTotal = row.status.containerStatuses.length;
  const readyStatus = `${readyCount}/${containerTotal}`;
  return [restartCount, readyStatus];
});

const showDetail = ref(false);
// 展示Pod详情
const detail = (row) => {
  const item = JSON.parse(JSON.stringify(row));
  console.log(item);
  delete item.metadata.managedFields;
  // 把apiVersion和kind补上去
  const itemtemp = {
    apiVersion: "v1",
    kind: "Pod",
    metadata: item.metadata,
    spec: item.spec,
  };

  // 转成yaml
  const yamlData = obj2Yaml(itemtemp);
  data.yamlContent = yamlData;
  showDetail.value = true;
};



const closeWS = (ws)=>{
  ws.close()
  if (currentOptions.value == "exec") {
    term.reset()
  }
}

const attachTerm = (ws) =>{
    // attachaddon: 建立terminal和ws关联关系，实现webSocket消息自动管理
  console.log("建立terminal和ws关联关系，实现webSocket消息自动管理")
  var attachAddon = new AttachAddon(ws)
  //  aaa -> aaa, bbb -> bbb
  const oldSend = attachAddon._sendData;
  attachAddon._sendData = (data) => {
    const wsMessage = JSON.stringify({
      msgType: "input",
      data: data
    })
    return oldSend.call(attachAddon, wsMessage)
  }
  term.loadAddon(attachAddon)
}

// 执行命令和查看日志处理
const createWS = ()=>{
  let websocketUrl = ""
  logContent.value = []
  // ws wss: ws -> http  wss --> https
  // 1. npm run sit --> ws://127.0.0.1:8888   2. 部署后拿到当前的origin  http->ws  https->wss
  // 判断是否是sit环境
  let origin = ""
  if (import.meta.env.MODE == "sit") {
    origin = "ws://localhost:8081"
  } else {
    // 拿到当前域名
    let temp = window.location.origin
    // 把http换成ws
    origin = temp.replaceAll('http', 'ws')
    origin = origin.replaceAll('5173', '8081')
  }
  if (currentOptions.value == "logs"){
    websocketUrl = `${origin}/api/pod/logs?clusterId=${data.clusterId}&namespace=${data.namespace}&name=${currentPod.value.metadata.name}&container=${currentContainer.value}`
  } else if (currentOptions.value == "exec") {
    websocketUrl = `${origin}/api/pod/exec?clusterId=${data.clusterId}&namespace=${data.namespace}&name=${currentPod.value.metadata.name}&container=${currentContainer.value}&defaultCommand=${defaultCommand}`

  }
  let newWs = new WebSocket(websocketUrl);
  newWs.onopen=function(){console.log("链接建立时的事件")}
  newWs.onmessage = function(msgContent){
      if (currentOptions.value == "logs"){
        newWs.onmessage = function(msgContent) {
        console.log("接收到的消息",msgContent.data)
        // logContent.value.unshift(msgContent.data)
        logContent.value.push(msgContent.data)
      }
    } else if (currentOptions.value == "exec"){
      if (defaultCommand == "/bin/bash" && msgContent.data.indexOf("/bin/bash: no such file or directory")) {
          defaultCommand = "/bin/sh"
          const oldWs = curWs
          closeWS(oldWs)
          let newWs = createWS()
          attachTerm(newWs)
          curWs = newWs
      } 
    }
  }
  newWs.onerror=function(){
    console.log("错误链接")
    ElMessage({
      type: "error",
      message: "无法建立websocket链接"
    })
    // 关闭drawer
    beforeDrawerClose()
  }
  newWs.close=function(){
    console.log("关闭连接")
  };
  return newWs

}

const beforeDrawerClose =()=>{
    console.log("关闭socket链接")
    closeWS(curWs)
    if (currentOptions.value == "exec") {
      term.dispose()
    }
    drawer.value = false
}

const logExec = (row, arg) => {
    console.log("查看日志或执行命令")
    currentOptions.value = arg
    currentPod.value = row
    currentContainer.value = row.spec.containers[0].name
    const newWs = createWS()
    if (arg == "exec") {attachTerm(newWs)}
    curWs = newWs
    drawer.value =  true
}

// 更换容器
const containerChanged = () => {
  // 1. 断开之前的链接
  // 2. 重连websocket
  console.log("当前选择的容器是：", currentContainer.value)
  const oldWs = curWs
  closeWS(oldWs)
  console.log("当前选择的容器是2：", currentContainer.value)
  let newWs = createWS()
  attachTerm(newWs)
  curWs = newWs
}



const resizeTerm = ()=> {
  if (drawer.value == false) { return }
  fitAddon.fit()
  const h = window.innerHeight
  const w = window.innerWidth
  const msg = JSON.stringify({
    msgType: "resize",
    cols: w,
    rows: h
  })
  curWs.send(msg)
}
const openDrawer = ()=> {
  if (currentOptions.value == "exec") {
    // 绑定terminal到div
   
    term.open(document.getElementById('terminal'));
    term.write('\r\n集群连接成功!\r\n'); // 向终端写入成功消息
    console.log("绑定Terminal,term:", term)

    // 调整窗口大小, // 窗口尺寸变化时，终端尺寸自适应
    window.onresize = (event) => {
      resizeTerm()
    }
    term.focus()
  }
}
const { yamlContent } = toRefs(data);
</script>

<template>
  <List title="Pod列表">
    <template #header-options>
      <ClusterNamespaceSelector
        @namespaceChangedRollback="rollback"
      ></ClusterNamespaceSelector>
      <el-input
        v-model="search"
        size="small"
        placeholder="搜索"
        style="width: 200px; margin-left: 20px; height: 32px"
      />
    </template>
    <template #main>
      <el-table
        border
        height="480"
        v-if="data.items"
        :data="filterTableData"
        style="width: 100%"
      >
        <el-table-column fixed prop="" align="center" label="名称" width="320">
          <template #default="scope">
            <el-button link type="primary" @click="detail(scope.row)">{{
              scope.row.metadata.name
            }}</el-button>
          </template>
        </el-table-column>
        <el-table-column
          prop="metadata.creationTimestamp"
          align="center"
          label="创建时间"
          width="180"
        />
        <el-table-column
          prop="metadata.namespace"
          align="center"
          label="命名空间"
          width="180"
        />
        <el-table-column
          prop=""
          align="center"
          label="状态"
          width="80"
          sortable
        >
          <template #default="scope">
            <span
              v-if="scope.row.status.phase == 'Running'"
              style="color: green"
              >Running</span
            >
            <span v-else style="color: red">{{ scope.row.status.phase }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="" align="center" label="重启次数" width="80">
          <template #default="scope">
            <span v-if="!scope.row.metadata.deletionTimestamp">{{
              getPodRestartCount(scope.row)[0]
            }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="" align="center" label="容器状态" width="80">
          <template #default="scope">
            <span v-if="!scope.row.metadata.deletionTimestamp">{{
              getPodRestartCount(scope.row)[1]
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          prop="status.podIP"
          align="center"
          label="Pod IP"
          width="180"
        />
        <el-table-column
          prop="spec.nodeName"
          align="center"
          label="宿主机主机名"
          width="180"
        />
        <el-table-column
          prop="status.hostIP"
          align="center"
          label="宿主机IP"
          width="180"
        />
        <el-table-column fixed="right" label="操作" align="center" width="180">
          <template #default="scope">
            <el-button v-if="!scope.row.metadata.deletionTimestamp" link type="warning" @click="deleteItem(scope.row)">删除</el-button>
            <el-button link type="warning" @click="logExec(scope.row,'exec')">执行命令</el-button>
            <el-button link type="warning" @click="logExec(scope.row,'logs')">查看日志</el-button>
          </template>
        </el-table-column>
      </el-table>
    </template>
  </List>

  <el-dialog destroy-on-close v-model="showDetail" width="70%">
    <template #header="{ titleId, titleClass }">
      <div class="my-header">
        <div :id="titleId" :class="titleClass" style="margin: 10px auto 0 auto">
          <el-button type="primary" title="资源所在的集群">
            <i class="iconfont icon-kubernetes" style="font-size: 30px" />
            <span style="font-size: 20px">{{ data.clusterId }}</span>
          </el-button>
          <el-button type="primary" title="资源所在的命名空间">
            <i class="iconfont icon-namepsace" style="font-size: 30px" />
            <span style="font-size: 20px">{{ data.namespace }}</span>
          </el-button>
        </div>
      </div>
    </template>

    <CodeMirror v-model="yamlContent"></CodeMirror>
  </el-dialog>

  <!-- drawer -->
  <el-drawer
    v-model="drawer"
    direction="btt"
    :before-close="beforeDrawerClose"
    :with-header="false"
    @opened="openDrawer"
    size="50%"
  >
    <div style="display: flex; margin-bottom: 10px;">
        <el-icon><i class="iconfont icon-Pod"></i></el-icon>
        <span style="font-size:20px;">{{ currentPod.metadata.name }}</span>
        <el-radio-group v-model="currentContainer" style="margin-left:20px;">
            <el-radio @change="containerChanged()"  v-for="c in currentPod.spec.containers" :label="c.name">{{ c.name }}</el-radio>
        </el-radio-group>
    </div>
    <div>
        <!-- 日志 -->
        <template v-if="currentOptions=='logs'">
          <el-table :data="logContent" style="width:100%;">
            <el-table-column>
              <template #default="scope">
                {{ scope.row }}
              </template>
            </el-table-column>
          </el-table>
        </template>
        <!-- 命令 -->
        <template v-else-if="currentOptions=='exec'">
          <div id="terminal" style="text-align:left;"></div>
        </template>
    </div>
  </el-drawer>
</template>


<style scoped>
.my-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  gap: 16px;
}
</style>